package top.vains.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import top.vains.entity.Permission;
import top.vains.entity.Result;
import top.vains.entity.customer.Pagination;
import top.vains.entity.customer.PermissionCustomer;
import top.vains.enumeration.ResultEnum;
import top.vains.exception.CustomerException;
import top.vains.service.IPermissionService;
import top.vains.util.ResultUtils;

import java.util.*;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author vains
 * @since 2020-02-17
 */
@Slf4j
@RestController
@RequestMapping("/permission")
@Api(tags = "权限操作接口，权限包括导航与按钮")
public class PermissionController {

    private final IPermissionService permissionService;

    private final ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Autowired
    public PermissionController(IPermissionService permissionService, ShiroFilterFactoryBean shiroFilterFactoryBean) {
        this.permissionService = permissionService;
        this.shiroFilterFactoryBean = shiroFilterFactoryBean;
    }


    @GetMapping("/getMenus")
    @ApiOperation(value = "获取所有的导航栏", notes = "获取所有的导航栏")
    public Result getMenus() {
        List<Permission> permissions = permissionService.selectMenus();
        return ResultUtils.success(ResultEnum.SUCCESS.getMessage(), permissions);
    }

    @PostMapping("/insertPermission")
    @ApiOperation(value = "添加资源", notes = "添加资源")
    public Result insertPermission(@RequestBody Permission permission) {
        permission.setAuthorization(StringUtils.isEmpty(permission.getAuthorization()) ? "anon" : permission.getAuthorization());
        permissionService.save(permission);
        updatePermission(permissionService);
        return ResultUtils.success("添加成功！");
    }

    @PostMapping("/updatePermission")
    @ApiOperation(value = "修改资源", notes = "修改资源")
    public Result updatePermission(@RequestBody Permission permission) {
        permissionService.updateById(permission);
        updatePermission(permissionService);
        return ResultUtils.success("修改成功！");
    }

    @GetMapping("/getPermissions")
    @ApiOperation(value = "获取所有的资源", notes = "包括上级节点的名称")
    public Result getPermissions(Pagination pagination, String name) {
        name = name == null ? "" : name;
        Page<Object> page = PageMethod.startPage(pagination.getCurrent(), pagination.getSize());
        List<PermissionCustomer> permissions = permissionService.selectPermissionsDetails(name);
        pagination.setTotal(page.getTotal());
        pagination.setData(permissions);
        return ResultUtils.success(ResultEnum.SUCCESS.getMessage(), pagination);
    }

    @GetMapping("/getPermission")
    @ApiOperation(value = "获取所有的资源", notes = "包括上级节点的名称")
    public Result getPermission() {
        QueryWrapper<Permission> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", false);
        List<Permission> list = permissionService.list(wrapper);
        return ResultUtils.success(ResultEnum.SUCCESS.getMessage(), list);
    }

    @PutMapping("/deletePermissionByIds")
    @ApiOperation(value = "根据ID删除资源", notes = "适用一个或多个")
    public Result deletePermissionById(@RequestBody List<Integer> ids) {
        List<Permission> permissions = new ArrayList<>();
        for (Integer id : ids) {
            Permission permission = new Permission();
            permission.setNavId(id);
            permission.setDeleted(true);
            permissions.add(permission);
        }
        permissionService.updateBatchById(permissions);
        return ResultUtils.success("删除成功！");
    }

    /**
     * 更新shiro拦截工厂的权限信息
     */
    private synchronized void updatePermission(IPermissionService permissionService) {
        Map<String, String> filterMap = new LinkedHashMap<>();
        // 更新之后获取需要验证的权限
        List<Permission> permissions = permissionService.selectPermissions();
        for (Permission permission1 : permissions) {
            // 排除不需要验证的权限
            if (!Objects.equals("anon", permission1.getAuthorization())) {
                // 组装权限的拦截规则
                String perms = "jwt,perms[" + permission1.getAuthorization() + "]";
                filterMap.put(permission1.getPageUrl(), perms);
            }
        }
        AbstractShiroFilter shiroFilter;
        try {
            shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            if (shiroFilter != null) {
                // 获取过滤拦截器
                PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
                DefaultFilterChainManager filterManager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
                // 清空拦截器中的存储
                filterManager.getFilterChains().clear();
                // 清空拦截工厂中的存储，如果不清除这里，还会把之前的带进去
                shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
                // 相当于重建一个Map，因为上边已经清空了
                Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
                // 把修改后的map全部放进去
                chains.putAll(filterMap);
                Set<Map.Entry<String, String>> entries = filterMap.entrySet();
                // 这个相当于全量添加
                for (Map.Entry<String, String> entry : entries) {
                    // 要拦截的url地址
                    String url = entry.getKey().trim().replace(" ", "");
                    // 地址对应的权限
                    String chainDefinition = entry.getValue().trim().replace(" ", "");
                    // 生成拦截
                    filterManager.createChain(url, chainDefinition);
                }
            }
        } catch (Exception e) {
           log.info("权限更新失败，原因：", e);
           throw new CustomerException("权限更新失败");
        }
    }

}
